package strutil

import (
	"bytes"
	"crypto/md5"
	"encoding/hex"
	"math/rand"
	"path"
	"runtime"
	"strings"
	"time"
	"unicode"
)

const (
	Empty           = ""                                                               // 空字符串
	Comma           = ","                                                              // 逗号
	Space           = " "                                                              // 空格
	Underline       = "_"                                                              // 下划线
	Colon           = ":"                                                              // 冒号
	Dash            = "-"                                                              // 短横线
	Dot             = "."                                                              // 点
	Asterisk        = "*"                                                              // 星号
	Slash           = "/"                                                              // 斜杠
	Zero            = "0"                                                              // 0
	One             = "1"                                                              // 1
	True            = "true"                                                           // true
	False           = "false"                                                          // false
	Goroutine       = "goroutine"                                                      // 协程字符串
	Json            = "json"                                                           // json
	Omitempty       = "omitempty"                                                      // omitempty
	LetterAndNumber = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" // 字母和数字
	Crlf            = "\r\n"                                                           // 回车换行
	Quote           = "\""                                                             // 双引号

	// CharSlash 字符
	CharSlash = '/' // 斜杠
	CharSpace = ' ' // 空格
)

func IsNotBlank(str string) bool {
	return str != Empty
}

func IsBlank(str string) bool {
	return str == Empty
}

func RandStr(length int) string {
	bs := []byte(LetterAndNumber)
	var result []byte
	rand.New(rand.NewSource(time.Now().UnixNano() + int64(rand.Intn(100))))
	for i := 0; i < length; i++ {
		result = append(result, bs[rand.Intn(len(bs))])
	}
	return string(result)
}

func JoinPaths(absolutePath, relativePath string) string {
	if IsBlank(relativePath) {
		return absolutePath
	}

	finalPath := path.Join(absolutePath, relativePath)
	if LastChar(relativePath) == CharSlash && LastChar(finalPath) != CharSlash {
		return finalPath + Slash
	}
	return finalPath
}

func LastChar(str string) uint8 {
	if IsBlank(str) {
		panic("The length of the string can't be 0")
	}
	return str[len(str)-1]
}

func SpitNotLetterAndNumber(str string) []string {
	return strings.FieldsFunc(str, func(c rune) bool {
		// 返回true：表示分割，false：表示保留
		// 表示非字母和数字需要分割
		return !unicode.IsLetter(c) && !unicode.IsNumber(c)
	})
}

func Equals(sor string, tar string) bool {
	return sor == tar
}

func EqualsIgnoreCase(sor string, tar string) bool {
	return strings.ToUpper(sor) == strings.ToUpper(tar)
}

// GetCurrentGid 获取当前协程id
func GetCurrentGid() string {
	bs := make([]byte, 64)
	bs = bs[:runtime.Stack(bs, false)]
	bs = bytes.TrimPrefix(bs, []byte(Goroutine+Space))
	bs = bs[:bytes.IndexByte(bs, CharSpace)]
	return string(bs)
}

// MD5 将字符串进行md5加密处理
func MD5(data string) string {
	resultArr := md5.Sum([]byte(data))
	return hex.EncodeToString(resultArr[:])
}

// FirstLetter2Lower 将字符串的首字母转换为小写（小驼峰）
func FirstLetter2Lower(str string) string {
	sLen := len(str)
	if sLen == 0 {
		return Empty
	}
	newSli := make([]byte, 0, sLen)
	firstChar := str[0]
	if isUpper := firstChar >= 'A' && firstChar <= 'Z'; isUpper {
		firstChar += 'a' - 'A'
		newSli = append(newSli, firstChar)
	}
	if sLen > 1 {
		newSli = append(newSli, str[1:]...)
	}
	return string(newSli)
}

// NameSnake 将字符串转换为小写下划线
func NameSnake(name string) string {
	snakeNameSli := make([]byte, 0)
	for i := 0; i < len(name); i++ {
		c := name[i]
		if isUpper := c >= 'A' && c <= 'Z'; isUpper {
			if i > 0 {
				snakeNameSli = append(snakeNameSli, '_')
			}
			c += 'a' - 'A'
		}
		snakeNameSli = append(snakeNameSli, c)
	}
	return string(snakeNameSli)
}

// IsChinese 判断字符是否为中文字符
func IsChinese(r rune) bool {
	return unicode.Is(unicode.Han, r) || // 基本汉字
		r >= 0x3400 && r <= 0x4DBF || // 扩展A区
		r >= 0x4E00 && r <= 0x9FFF || // 基本汉字
		r >= 0xF900 && r <= 0xFAFF || // 兼容汉字和部首扩展区
		r >= 0x3000 && r <= 0x303F || r >= 0xFF00 && r <= 0xFFEF // 检查是否在中文全角标点符号范围
}
